<?php
namespace CongoSSO;

require_once(dirname(__FILE__) . '/JWT.php');
require_once(dirname(__FILE__) . '/Request.php');

class Token {
    public $token;
    public $userInfo;
    # 过期时间
    public $exp;

    public function __construct($token, $userInfo, $exp = null) {
        $this->token = $token;
        $this->userInfo = $userInfo;
        $this->exp = $exp;
    }
}

class OAuthClient {
    public $token;

    protected $config;
    protected $appKey;
    protected $secretKey;
    protected $oauthUrl;
    protected $ssoClientServer;

    public const SUCCESS_CODE = 200;
    public const FAILED_CODE = 201;
    public const HTTP_STATUS_CREATED = 201;
    public const HTTP_STATUS_UNAUTHORIZED = 401;

    public function __construct($appKey, $secretKey) {
        $this->config = include(dirname(__FILE__) . '/conf.php');
        $this->appKey = $appKey;
        $this->secretKey = $secretKey;
        $this->oauthUrl = trim($this->config['SSO_SERVER_URL'], ' /');
    }

    public function setSSOClientServerUrl($ssoClientServer) {
        $this->ssoClientServer = $ssoClientServer;
    }

    public function getTokenByTicket($ticket) {
        $token = $this->getToken($ticket);

        if($token) {
            $this->token = $token;
            $data = array(
                'token' => $token->token,
                'userInfo' => array(
                    'avatar' => $token->userInfo['avatar'],
                    'mobile' => $token->userInfo['mobile'],
                    'nickName' => $token->userInfo['nickName'],
                    'userId' => $token->userInfo['userId']
                )
            );
            $result = array(
                'code' => self::SUCCESS_CODE,
                'data' => $data
            );
        } else {
            $result = array('code' => self::FAILED_CODE, 'data' => null);
        }

        return $result;
    }

    public function getToken($ticket) {
        if(!isset($this->ssoClientServer)) {
            throw new Exception("SSO Client Server IS NULL");
        }
        if(!isset($this->oauthUrl)) {
            throw new Exception("OAUTH HOST IS NULL");
        }

        $params = array(
            'ticket' => $ticket,
            'appKey' => $this->appKey,
            'server' => $this->ssoClientServer,
        );

        $url = $this->oauthUrl . $this->config['OAUTH_PATH_GET_TOKEN'];

        $result = Request::post($url, $params);
        if ($result && $result['succ']) {
            $result = json_decode($result['result'], JSON_OBJECT_AS_ARRAY);

            if ($result['code'] == self::SUCCESS_CODE) {
                $exp = $this->checkToken($result['data']['OSAuth']);
                if (!$exp) {
                    return;
                }
                $token = new Token(
                    $result['data']['OSAuth'],
                    $result['data']['userInfo'],
                    $exp
                );
                return $token;
            } else {
                error_log("OauthClient getToken error: " . json_encode($result, JSON_UNESCAPED_UNICODE), 0);
                return;
            }
        } else {
            error_log("OauthClient getToken error: " . json_encode($result, JSON_UNESCAPED_UNICODE), 0);
            return;
        }
    }

    /**
     * 验证 jwt token
     * @param $token
     * @return bool | string 验证失败返回 false, 验证成功返回 token 过期时间
     */
    public function checkToken($token) {
        try {
            $claims = JWT::decode($token, $this->secretKey);
            if (!$claims) {
                error_log("Invalid Token: empty payload", 0);
                return false;
            }
            return $claims['exp'];
        } catch (\UnexpectedValueException $e) {
            error_log("Invalid Token: " . json_encode($e, JSON_UNESCAPED_UNICODE), 0);
            return false;
        } catch (Utils\BeforeValidException $e) {
            error_log("Expired Token: " . json_encode($e, JSON_UNESCAPED_UNICODE), 0);
            return false;
        } catch (Utils\ExpiredException $e) {
            error_log("Expired Token: " . json_encode($e, JSON_UNESCAPED_UNICODE), 0);
            return false;
        } catch (Utils\SignatureInvalidException $e) {
            error_log("Illegal Token: " . json_encode($e, JSON_UNESCAPED_UNICODE), 0);
            return false;
        }
    }
}
?>
